package org.ribizli.games.amoeba;

import java.util.Map;

import org.ribizli.games.amoeba.FieldView.OnMarkListener;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnCancelListener;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class GameActivity extends Activity implements OnMarkListener {
  final static String TAG = "Amoeba-GameActivity";
	private FieldView mFieldView;
	private BackgroudService mBGService;
	private String mProgressText = "";
  private boolean mLogged;
  private int mState = 0;
	private boolean mMoveSent = false;
  private TextView mPlayerName;
  private TextView mPlayerScore;
  private TextView mOpponentName;
  private TextView mOpponentScore;
  private TextView mOnlineStatus;

	private final static int STATE_NOT_LOGGED_IN = 0;
	private final static int STATE_LOGGED_IN = 1;
	private final static int STATE_STARTING = 2;
	private final static int STATE_WAITING = 3;
	private final static int STATE_IN_GAME = 4;
	private final static int STATE_END_GAME = 5;


	private final static int DIALOG_LOGIN = 0;
	private final static int DIALOG_REGISTER = 1;
	private final static int DIALOG_PROGRESS = 2;
  private final static int DIALOG_WELCOME = 3;

	private final static int MENU_LOGIN = 0;
  private final static int MENU_REGISTER = 1;
  private final static int MENU_LOGOUT = 2;
  private final static int MENU_NEWGAME = 3;
  private final static int MENU_PREFERENCES = 4;
  private final static int MENU_REMATCH = 5;
  private final static int MENU_COUNT = 6; // the count of the above menu items

  final static String PREF_USERNAME = "username";
  final static String PREF_PASSWORD = "password";
	

  private class MyListener extends BackgroudService.BasicBGServiceListener {
	  
    @Override
		public void userStatistics(int online, int playing) {
			Log.d(TAG, "online / playing: " + online + " / " + playing);
			mOnlineStatus.setText(getResources().getString(R.string.onlineStatusMessage, online, playing));
		}

		@Override
		public void error(String msg) {
			hideProgressDialog();
			Log.e(TAG, "Error: " + msg);
			String message = null;
			if (BackgroudService.ERROR_USER_ALREADY_REGISTERED.equals(msg)) {
				mState = STATE_NOT_LOGGED_IN;
			  message = getResources().getString(R.string.errorAlreadyRegistered);
			  showDialog(DIALOG_REGISTER);
			} else if (BackgroudService.ERROR_USER_NOT_REGISTERED.equals(msg)) {
				mState = STATE_NOT_LOGGED_IN;
				saveCredentials(null, null);
			  message = getResources().getString(R.string.errorNotRegistered);
			  showDialog(DIALOG_LOGIN);
			} else if (BackgroudService.ERROR_WRONG_PASSWORD.equals(msg)) {
				mState = STATE_NOT_LOGGED_IN;
        saveCredentials(null, null);
			  message = getResources().getString(R.string.errorWrongPassword);
			  showDialog(DIALOG_LOGIN);
			} else if (BackgroudService.ERROR_INVALID_TOKEN.equals(msg) || BackgroudService.ERROR_USER_NOT_LOGGED.equals(msg)) {
				mState = STATE_NOT_LOGGED_IN;
				mFieldView.setEnabled(false);
			  message = getResources().getString(R.string.errorNotLogged);
			  showDialog(DIALOG_LOGIN);
			} else if (BackgroudService.ERROR_NETWORK_ERROR.equals(msg)) {
				if (mState == STATE_IN_GAME && mMoveSent) {
					// TODO: move coudn't be sent
				  message = getResources().getString(R.string.moveNotSent);
					Log.w(TAG, "Move cound't be sent");
				}
			} else {
			  message = msg;
			}
			if (message != null)
				Toast.makeText(GameActivity.this, message, Toast.LENGTH_LONG).show();
			
			mLogged = mBGService.isLogged();
		}

		@Override
    public void messageFrom(String opponent, String message) {
		  Toast.makeText(GameActivity.this, opponent + ": " + message, Toast.LENGTH_LONG).show();
		  // TODO create a messageing dialog
    }

    @Override
		public void loggedIn(String username, int score) {
			hideProgressDialog();
			mLogged = true;
			mState = STATE_LOGGED_IN;
			showDialog(DIALOG_WELCOME);
			mPlayerName.setText(username);
			mPlayerScore.setText(String.valueOf(score));
		}

    @Override
    public void loggedOut() {
      hideProgressDialog();
      mLogged = false;
      mState = STATE_NOT_LOGGED_IN;
      mPlayerName.setText("");
      mPlayerScore.setText("");
      //showDialog(DIALOG_LOGIN);
    }

    @Override
    public void registered(String u, String p) {
      showProgressDialog(R.string.progress_loggingIn);
      login(u, p);
    }

    @Override
    public void newGame(String opponent, int oppScore, boolean youFirst) {
      hideProgressDialog();
      mFieldView.clear();
      mOpponentName.setText(opponent);
      mOpponentScore.setText(String.valueOf(oppScore));
      String message = getResources().getString(R.string.newGameMessage, opponent);
      if (youFirst) {
        message += " " + getResources().getString(R.string.yourTurn);
      }
      Toast.makeText(GameActivity.this, message, Toast.LENGTH_LONG).show();
      boldName(youFirst);
      mFieldView.setEnabled(youFirst);
      mState = STATE_IN_GAME;
      dismissDialog(DIALOG_WELCOME);
    }

    @Override
		public void opponentLeft() {
    	mState = STATE_LOGGED_IN;
    	mFieldView.setEnabled(false);
      mOpponentName.setText("");
      mOpponentScore.setText("");
    	Toast.makeText(GameActivity.this, R.string.opponentLeft, Toast.LENGTH_LONG).show();
		}

		@Override
		public void rematch() {
      Toast.makeText(GameActivity.this, R.string.opponentRematch, Toast.LENGTH_LONG).show();
		}

		@Override
		public void youLoose(int x, int y, int yourScore, int oppScore,
				int[][] winnerRow) {
			mState = STATE_END_GAME;
      mFieldView.putOpponentMark(x, y);
    	mFieldView.setEnabled(false); // it must be already disabled
    	mFieldView.markWinnerRow(winnerRow);
    	mPlayerScore.setText(String.valueOf(yourScore));
      mOpponentScore.setText(String.valueOf(oppScore));
      Toast.makeText(GameActivity.this, R.string.youLost, Toast.LENGTH_LONG).show();
		}

		@Override
		public void yourTurn(int oppX, int oppY) {
			mFieldView.putOpponentMark(oppX, oppY);
			mFieldView.setEnabled(true);
			boldName(true);
      Toast.makeText(GameActivity.this, R.string.yourTurn, Toast.LENGTH_SHORT).show();
		}

		@Override
		public void youWon(int yourScore, int oppScore, int[][] winnerRow) {
			mState = STATE_END_GAME;
    	mFieldView.setEnabled(false);
      mFieldView.markWinnerRow(winnerRow);
      mPlayerScore.setText(String.valueOf(yourScore));
      mOpponentScore.setText(String.valueOf(oppScore));
      Toast.makeText(GameActivity.this, R.string.youWon, Toast.LENGTH_LONG).show();
		}

		@Override
    public void waitingForOpponent() {
      showProgressDialog(R.string.progress_waitingForOpponent);
			mState = STATE_WAITING;
    }
	}
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
    Log.d(TAG, "onCreate");
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.game);
		mBGService = ((ApplicationEx)getApplication()).getBackgroudService();
		mBGService.setListener(new MyListener());
		mLogged = mBGService.isLogged();
		mFieldView = (FieldView)findViewById(R.id.field);
		mFieldView.setEnabled(false);
		mFieldView.setOnMarkListener(this);
		mPlayerName = (TextView)findViewById(R.id.playerName);
    mPlayerScore = (TextView)findViewById(R.id.playerScore);
    mOpponentName = (TextView)findViewById(R.id.opponentName);
    mOpponentScore = (TextView)findViewById(R.id.opponentScore);
    mOnlineStatus = (TextView)findViewById(R.id.onlineStatus);
	}

  @Override
  protected void onRestart() {
    super.onRestart();
    Log.d(TAG, "onRestart");
  }

  @Override
  protected void onStart() {
    super.onStart();
    Log.d(TAG, "onStart");
  }

  @Override
  protected void onResume() {
    super.onResume();
    Log.d(TAG, "onResume");
    if (!mLogged) {
      login(null, null);
    }
  }

  @Override
  protected void onPause() {
	  super.onPause();
	  Log.d(TAG, "onPause");
	  // TODO: test this out with incoming call (??? how to handle this)
    mBGService.logout();
  }

  @Override
  protected void onStop() {
    super.onStop();
    Log.d(TAG, "onStop");
  }
  
  @Override
  protected void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy");
  }

	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog;
		switch (id) {
		case DIALOG_LOGIN:
			dialog = new LoginDialog(this);
			break;
		case DIALOG_REGISTER:
			dialog = new RegisterDialog(this);
			break;
		case DIALOG_PROGRESS:
			dialog = new ProgressDialog(this);
			dialog.setCancelable(true);
			dialog.setOnCancelListener(new OnCancelListener() {
        @Override
        public void onCancel(DialogInterface dialog) {
          if (mState == STATE_WAITING || mState == STATE_STARTING) {
            // registered for a new game, cannot leave
            Toast.makeText(GameActivity.this, R.string.cannotLeaveQueue, Toast.LENGTH_LONG).show();
          } else {
            mBGService.cancelCurrent();
          }
        }
      });
			break;
		case DIALOG_WELCOME:
		  dialog = new Dialog(this);
		  dialog.setContentView(R.layout.welcome);
		  dialog.setTitle(R.string.welcomeTitle);
		  Button newGame = (Button) dialog.findViewById(R.id.welcome_newGame);
		  final Dialog d = dialog;
		  newGame.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
          d.dismiss();
          newGame();
        }});
		  break;
		default:
			dialog = null;
		}
		return dialog;
	}
	
	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		super.onPrepareDialog(id, dialog);
		if (id == DIALOG_PROGRESS) {
			((ProgressDialog)dialog).setMessage(mProgressText);
		}
	}

	private void showProgressDialog(int res) {
	  mProgressText = getResources().getString(res);
	  showDialog(DIALOG_PROGRESS);
	}
	
	void hideProgressDialog() {
		dismissDialog(DIALOG_PROGRESS);
	}
	
	void login(String u, String p) {
	  if (u == null || p == null) {
      SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
      if (prefs.contains(PREF_USERNAME) && prefs.contains(PREF_PASSWORD)) {
        u = prefs.getString(PREF_USERNAME, null);
        p = prefs.getString(PREF_PASSWORD, null);
      } else {
        showDialog(DIALOG_LOGIN);
        return;
      }
	  }
    showProgressDialog(R.string.progress_loggingIn);
    mBGService.login(u, p);
	}
	
  void logout() {
    showProgressDialog(R.string.progress_loggingOut);
    mBGService.logout();
  }
  
  void register(String u, String p, Map<String, String> details) {
    showProgressDialog(R.string.progress_registering);
    mBGService.register(u, p, details);
  }
  
  void boldName(boolean yourTurn) {
    if (yourTurn) {
      mPlayerName.setTypeface(Typeface.DEFAULT_BOLD);
      mOpponentName.setTypeface(Typeface.DEFAULT);
    } else {
      mPlayerName.setTypeface(Typeface.DEFAULT);
      mOpponentName.setTypeface(Typeface.DEFAULT_BOLD);
    }
  }
  
  void saveCredentials(String u, String p) {
    SharedPreferences.Editor ed = getPreferences(Context.MODE_PRIVATE).edit();
    if (u == null) {
      ed.remove(PREF_USERNAME);
      ed.remove(PREF_PASSWORD);
    } else {
      ed.putString(PREF_USERNAME, u);
      ed.putString(PREF_PASSWORD, p);
    }
    ed.commit();
  }

  private void newGame() {
    mState = STATE_STARTING;
    mBGService.newGame();
    showProgressDialog(R.string.progress_startingNewGame);
  }

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO: set icons too
		menu.add(Menu.NONE, MENU_LOGIN, Menu.NONE, R.string.menu_login);
		MenuItem logout = menu.add(Menu.NONE, MENU_LOGOUT, Menu.NONE, R.string.menu_logout);
		logout.setVisible(false);
    menu.add(Menu.NONE, MENU_REGISTER, Menu.NONE, R.string.menu_register);
    MenuItem rematch = menu.add(Menu.NONE, MENU_REMATCH, Menu.NONE, R.string.menu_rematch);
    rematch.setVisible(false);
    MenuItem newgame = menu.add(Menu.NONE, MENU_NEWGAME, Menu.NONE, R.string.menu_newgame);
    newgame.setVisible(false);
    menu.add(Menu.NONE, MENU_PREFERENCES, Menu.NONE, R.string.menu_preferences);
		return true;
	}

	@Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    //return super.onPrepareOptionsMenu(menu);
    // if logged in
	  boolean[] visibleMenus = new boolean[MENU_COUNT];
	  switch (mState) {
    case STATE_NOT_LOGGED_IN:
      visibleMenus[MENU_PREFERENCES] = true;
      visibleMenus[MENU_LOGIN] = true;
      break;
    case STATE_LOGGED_IN:
      visibleMenus[MENU_LOGOUT] = true;
      visibleMenus[MENU_NEWGAME] = true;
      break;
    case STATE_STARTING:
      break;
    case STATE_WAITING:
      visibleMenus[MENU_LOGOUT] = true;
      break;
    case STATE_IN_GAME:
      visibleMenus[MENU_LOGOUT] = true;
      visibleMenus[MENU_NEWGAME] = true; // allow the player to leave and start a new game
      break;
    case STATE_END_GAME:
      visibleMenus[MENU_REMATCH] = true;
      visibleMenus[MENU_NEWGAME] = true;
      visibleMenus[MENU_LOGOUT] = true;
      break;
    default:
      break;
    }
	  
	  for (int i = 0; i < MENU_COUNT; i++) {
	    if (visibleMenus[i]) {
        menu.findItem(i).setVisible(true);
	    } else {
	      menu.findItem(i).setVisible(false);
	    }
	  }
	  return true;
  }

  @Override
	public boolean onOptionsItemSelected(MenuItem id) {
		switch (id.getItemId()) {
		case MENU_LOGIN:
			showDialog(DIALOG_LOGIN);
			break;
    case MENU_REGISTER:
      showDialog(DIALOG_REGISTER);
      break;
    case MENU_LOGOUT:
      logout();
      break;
    case MENU_NEWGAME:
    	newGame();
      break;
    case MENU_REMATCH:
      mState = STATE_WAITING;
      mBGService.rematch();
      showProgressDialog(R.string.progress_waitingForOpponent);
      break;
    case MENU_PREFERENCES:
    	startActivity(new Intent(this, Preferences.class));
    	break;
		default:
		}
		return false;
	}

	@Override
	public void onMark(int x, int y) {
	  mFieldView.setEnabled(false);
		mBGService.makeMove(x, y);
		boldName(false);
		mMoveSent  = true;
	}
}